#include <stdio.h>

typedef int myInt;
typedef myInt myInt2;

/*
 * Test general small things
 */
void generalTest() {
  //Explicit conversion
  int k = (int) (15.9 + 7);
  printf("%i \n", k);

  //Constant with conversion
  const int l = (int) 11.2;

  //Condition statement using implicit conversions
  if((l > 10.5) && ((k+0.5) > 20)) {
    k = 1;
  } else {
    k = 2;
  }

  //While, continue, break
  while(k < 10) {
    if(k == 5) {
      k = k+2;
      continue;
    }
    if(k == 9) {
      k = k + 10;
      break;
    }
    k = k+1;
  }
  printf("Result of k after some calculations: %i \n", k);//k started with 1, double at 5 and add 10 at 9 and break then so: k=19

  //Advanced expression
  float c = ((1 + 2 + 3)*((-1+3+1-1)*2.5))/((3.5-2.5)*2); //(6*5)/2 so c = 15
  printf("Result of advanced expression: %f \n", c);
}

/*
 * Multiple parameters, return of expression
 * Forward declaration test 
 */
int sum(int a, int b);

int sum(int a, int b) {
  return a + b;
}

/*
 * Recursive Fibonacci-function
 * This function can be used to test for return statements
 */
int fibonacci(int n) {
  if(n == 0) {
    return 0;
  } else {
    if(n == 1) {
      return 1;
    } else {
      return fibonacci(n-1)+fibonacci(n-2);
    }
  }
}

/*
 * Test for fibonacci
 */
void testFibonacci() {
  int n;
  printf("How much Fibonacci numbers should I calculate? \n");
  scanf("%i", n);
  printf("First %i Fibonacci numbers: \n", n);
  int i = 0;
  while(i < n) {
    printf("%d \n", fibonacci(i));
    i = i+1;
  }
}

/*
 * Conversion of sum of two floats to integer
 */
int floatToInt(float i, float j) {
  return (int) (i + j);
}

/*
 * Calculates sum of two floats. 
 */
float floatSum(float i, float j) {
  return i + j;
}

/*
 * Faculty function using array
 */
int faculty(int n) {
  int a[n];

  //Initialize array
  int i = 0;
  while(i < n) {
    a[i] = i+1;
    i = i+1;
  }

  //Calculate result
  int result = 1;
  i = 0;
  while(i < n) {
    result = result * a[i];
    i = i+1;
  }

  return result;
}

/*
 * Array initialization
 */

int arraySum(int a, int b) {
  int c[2] = {a,b};
  return c[0]+c[1];
}

/*
 * Testfunction for testing semantical errors
 * Uncomment a statement to test the error
 */

void testErrors() {
  /* Non-existing function */
  //int a = nonExistingFunction();

  /*Parameter tests */
  float b;
  //b = floatSum(1); //To few parameters
  //b = floatSum(1,2,3.0); //To many parameters
  //b = floatSum(2.2, 'c'); //Incorrect parameter
  //int b2 = floatSum(2.2, 2.3); //Return type doesn't match variable type
  
  /* printf/scanf tests */
  //printf("%i", b); //Wrong parameter type (should be of integer type)
  //printf("%i"); //Not enough arguments
  //printf("%i", 1, 1.2); //Too many arguments

  /* Reassignment of constant */
  const int cst = 1;
  //cst = 2;

  /* Unallowed statements in this context */
  //break;
  //continue;
  //return; //No return-statements allowed in our functions with void as return type

  /* Array tests */
  //int array['a'];

  /* Wrong types */
  //int i1 = 5.2;
  //char c1 = arraySum(2,8);
  //int z = (float) 9;

  /* Condition errors */
  //if(5 * 6) { } //Unvalid expression
  
  /* Other small error checks */
  //int y = g0; //Undefined variable
}

/*
 * Main-function
 */
int main() {
  /* Uncomment for error testing.. */
  //testErrors();

  //General test
  generalTest();

  //Conversion of result of a function call
  int i = (int) floatSum(5.3, 7.8);
  printf("%i \n", i);

  //Fibonacci test
  testFibonacci();

  //Faculty test
  int fac;
  printf("Calculate faculty of:\n");
  scanf("%i", fac);
  int result = faculty(fac);

  printf("Result of %i! : %i \n", fac, result);

  //Printf/scanf tests
  char a[20];
  printf("Enter some (max. 20) characters, with the escape character as final character.. \n");
  scanf("%s", a);
  printf("You entered: %s \n", a);

  //Array initialization test
  printf("Array initialization result: %i \n", arraySum(2,3));

  //Typedef test
  myInt a1 = 1;
  myInt2 b1 = 8;
  printf("Result of myInt sum: %i \n", a1+b1);

  //Optimization: constant expression is calculated, so amount of instructions is reduced
  int optim = (1+1)*2*(1+(-1)+1); //just "ldc i 4" instead of whole calculation!

  return 0;
}
